﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;
using System.Reflection;


namespace Marmat.Forms
{
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(DropDownBox), "dropDownBox_icon.png")]
    public partial class DropDownBox : TextBox
    {
        internal DevExpress.XtraEditors.Controls.EditorButton comboButton;
        private DevExpress.XtraEditors.Controls.EditorButton command;

        public DropDownBox()
        {

            // 此调用是设计器所必需的。
            this.InitializeComponent();

            // 在 InitializeComponent() 调用之后添加任何初始化。
            this.comboButton = new DevExpress.XtraEditors.Controls.EditorButton(DevExpress.XtraEditors.Controls.ButtonPredefines.Combo);
            this.command = new DevExpress.XtraEditors.Controls.EditorButton();
            this.TextEdit1.Properties.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] { this.comboButton, this.command });
            this.BaseEdit.BringToFront();
        }

        /// <summary>
        /// 获取或设置此控件的数据源。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [DefaultValue(null)]
        [AttributeProvider(typeof(IListSource))]
        [Category("数据")]
        [Description("获取或设置此控件的数据源。")]
        public virtual object DataSource
        {
            get
            {
                return this.m_DataSoure;
            }

            set
            {
                this.m_DataSoure = value;
                if (this.BaseEdit is object)
                {
                    this.BaseEdit.Refresh();
                }
            }
        }

        private object m_DataSoure;


        /// <summary>
        /// 获取或设置要为此 System.Windows.Forms.ListControl 显示的属性。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [DefaultValue(null)]
        [Category("数据")]
        [Description("获取或设置要为此 System.Windows.Forms.ListControl 显示的属性。")]
        public virtual string DisplayMember
        {
            get
            {
                return this.m_DisplayMember;
            }

            set
            {
                this.m_DisplayMember = value;
                if (this.DataSource is object)
                {
                    this.DataSource = this.DataSource;
                }
            }
        }

        private string m_DisplayMember;

        /// <summary>
        /// 获取或设置一个属性，该属性将用作 System.Windows.Forms.ListControl 中的项的实际值。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [DefaultValue(null)]
        [Category("数据")]
        [Description("获取或设置一个属性，该属性将用作 System.Windows.Forms.ListControl 中的项的实际值。")]
        public virtual string ValueMember
        {
            get
            {
                return this.m_ValueMember;
            }

            set
            {
                this.m_ValueMember = value;
                if (this.DataSource is object)
                {
                    this.DataSource = this.DataSource;
                }
            }
        }

        private string m_ValueMember;

        /// <summary>
        /// 是否显示下拉按钮。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [DefaultValue(true)]
        [Category("外观")]
        [Description("是否显示下拉按钮。")]
        public virtual bool ShowDropDownButton
        {
            get => this.TextEdit1.Properties.Buttons[0].Visible;
            set => this.TextEdit1.Properties.Buttons[0].Visible = value;
        }

        /// <summary>
        /// 是否显示命令按钮。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [DefaultValue(true)]
        [Category("外观")]
        [Description("是否显示命令按钮。")]
        public virtual bool ShowModalButton
        {
            get => this.TextEdit1.Properties.Buttons[1].Visible;
            set => this.TextEdit1.Properties.Buttons[1].Visible = value;
        }

        /// <summary>
        /// 获取或设置下拉窗体的实例。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [Browsable(false)]
        [DefaultValue(null)]
        public virtual PopupControl PopupControl
        {
            get => this.m_PopupControl;
            set
            {
                this.m_PopupControl = value;
                this.TextEdit1.Properties.PopupControl = value;
            }
        }

        private PopupControl m_PopupControl;

        /// <summary>
        /// 打开下拉窗体。
        /// </summary>
        /// <remarks></remarks>
        public virtual void ShowDropDownForm()
        {
            this.TextEdit1.ShowPopup();
        }

        /// <summary>
        /// 关闭已经显示的下拉窗口。
        /// </summary>
        /// <remarks></remarks>
        public void CloseDropDown()
        {
            this.TextEdit1.ClosePopup();
        }

        private void BDropDownBox_CustomDisplayText(object sender, CustomDisplayTextEventArgs e)
        {
            if (this.DataSource is object && !string.IsNullOrEmpty(this.ValueMember))
            {
                if (this.DataSource is DataTable)
                {
                    DataTable dataSource = (DataTable)this.DataSource;
                    foreach (DataRow dr in dataSource.Rows)
                    {
                        var item_Value = dr[this.ValueMember];
                        if (Equals(item_Value, e.Value) || this.EqualsValue(item_Value, e.Value))
                        {
                            if (!string.IsNullOrEmpty(this.DisplayMember))
                            {
                                e.DisplayText = dr[this.DisplayMember]?.ToString();
                            }
                            else
                            {
                                e.DisplayText = item_Value?.ToString();
                            }
                            return;
                        }
                    }
                }
                else if (this.DataSource is IEnumerable)
                {
                    IEnumerable dataSource = (IEnumerable)this.DataSource;
                    foreach (object item in dataSource)
                    {
                        if (item is null)
                            continue;
                        object item_value = null;
                        object item_display = null;
                        var members = item.GetType().GetMembers();
                        var member = members.FirstOrDefault(x => (x.Name ?? "") == (this.ValueMember ?? "") && (x is FieldInfo || x is PropertyInfo));
                        if (member is object)
                        {
                            if (member is FieldInfo field)
                                item_value = field.GetValue(item);
                            if (member is PropertyInfo property)
                                item_value = property.GetValue(item);
                        }
                        if (Equals(e.Value, item_value))
                        {
                            member = members.FirstOrDefault(x => (x.Name ?? "") == (this.DisplayMember ?? "") && (x is FieldInfo || x is PropertyInfo));
                            if (member is object)
                            {
                                if (member is FieldInfo field)
                                    item_display = field.GetValue(item);
                                if (member is PropertyInfo property)
                                    item_display = property.GetValue(item);
                            }
                            e.DisplayText = (!string.IsNullOrEmpty(this.DisplayMember) ? item_display : item_value)?.ToString();
                            return;
                        }
                    }
                }
            }
        }

        private bool EqualsValue(object value1, object value2)
        {
            if (value1 is int && value2 is long || value1 is long && value2 is int)
            {
                return value1 == value2;
            }
            else if (value1 is float && value2 is double || value1 is float && value2 is double)
            {
                return value1 == value2;
            }
            else if (value1 is float && value2 is decimal || value1 is float && value2 is decimal)
            {
                return value1 == value2;
            }
            else if (value1 is double && value2 is decimal || value1 is double && value2 is decimal)
            {
                return value1 == value2;
            }
            return false;
        }

        private void TextEdit1_QueryPopUp(object sender, CancelEventArgs e)
        {
            if (this.IsReadOnly == false)
            {
                DropDownFormOpening?.Invoke(this, e);
            }
            else
            {
                e.Cancel = true;
            }
        }

        private void TextEdit1_ButtonClick(object sender, DevExpress.XtraEditors.Controls.ButtonPressedEventArgs e)
        {
            if (!this.IsReadOnly)
            {
                if (e.Button == this.command)
                    this.ModalButtonClick?.Invoke(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// 在通过垃圾回收将 System.ComponentModel.Component 回收之前，释放非托管资源并执行其他清理操作。
        /// </summary>
        ~DropDownBox()
        {
            this.m_PopupControl?.Dispose();
        }
    }
}